from abc import ABCMeta, abstractmethod
from sqlalchemy.orm import Session
from docker import DockerClient

from app.dao.storage import delete_storage_by_service_id
from app.docker import Client


class StorageDeleter(metaclass=ABCMeta):
    @abstractmethod
    def delete(self):
        pass


class StorageDeleterImpl(StorageDeleter):
    service_id: str
    db: Session
    client: DockerClient
    network_name: str

    def __init__(self, db: Session, *, service_id: str, client: DockerClient) -> None:
        super().__init__()

        self.service_id = service_id
        self.db = db
        self.client = client

    def _delete_from_db(self):
        delete_storage_by_service_id(self.db, self.service_id)

    def _delete_datanode(self, namenodename: str):
        services = self.client.services.list()
        if len(services) == 0:
            return
        length = len(namenodename)
        for service in services:
            if service.name != namenodename and service.name[0:length] == namenodename:
                service.remove()

    def _delete_service(self):
        services = self.client.services.list(filters={'id': self.service_id})
        if len(services) == 0:
            return
        service = services[0]
        self.network_name = service.name
        if service.name[0:4] == "HDFS":
            self._delete_datanode(service.name)
        service.remove()

    def _delete_network(self):
        networks = self.client.networks.list(names=[self.network_name])
        if len(networks) == 0:
            return
        network = networks[0]
        network.remove()

    def delete(self):
        self._delete_from_db()
        self._delete_service()
        self._delete_network()


def get_storage_deleter(db: Session, *, service_id: str) -> StorageDeleter:
    return StorageDeleterImpl(db, service_id=service_id, client=Client().client)
